package com.example.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.example.anno.Log;
import com.example.constant.SeatTypeEnum;
import com.example.mapper.EventMapper;
import com.example.mapper.SeatMapper;
import com.example.mapper.TicketMapper;
import com.example.mapper.UserMapper;
import com.example.pojo.*;
import com.example.properties.AliPayProperties;
import com.example.service.EventService;
import com.example.service.SeatService;
import com.example.utils.AliSMS;
import com.example.utils.PathUtil;
import com.example.vo.EventVO;
import com.example.vo.SeatPurchasedVO;
import com.example.vo.SeatVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Log4j2
@Service
public class EventServiceImpl implements EventService {

    @Autowired
    private EventMapper eventMapper;
    @Autowired
    private SeatService seatService;
    @Autowired
    private SeatMapper seatMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TicketMapper ticketMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AliPayProperties aliPayConf;
    @Autowired
    private AliSMS aliSMS;

    @Override
    public EventVO getById(Integer eventID) {
        EventVO eventVO = new EventVO();
        eventVO.setLowSellout(false);
        eventVO.setMidSellout(false);
        eventVO.setHighSellout(false);
        Event event = eventMapper.getByID(eventID);
        Short place = event.getPlace();
        //将ticketVO中相同字段copy到ticket中,前面拷贝到后面
        BeanUtils.copyProperties(event, eventVO);
        //拿到所有的座位
        //所有的座位表
        List<Seat> seatList = seatMapper.list(place, null);
        // 座位分类
        List<Seat> lowSeat = seatList.stream().filter(seat -> Objects.equals(seat.getSeatType(), SeatTypeEnum.LOW_SEAT.getCode()))
                .collect(Collectors.toList());
        List<Seat> midSeat = seatList.stream().filter(seat -> Objects.equals(seat.getSeatType(), SeatTypeEnum.MID_SEAT.getCode()))
                .collect(Collectors.toList());
        List<Seat> highSeat = seatList.stream().filter(seat -> Objects.equals(seat.getSeatType(), SeatTypeEnum.HIGH_SEAT.getCode()))
                .collect(Collectors.toList());
        //拿到购买的票的封装
        SeatPurchasedVO seatPurchasedVOList = seatService.seatPurchased(eventID);
        //判断各种档次的票数与座位数是否相同，相同表示已经卖完了
        List<SeatVO> lowSeatVO = seatPurchasedVOList.getLowPriceSeats().stream()
                //true表示已被购买，
                .filter(seatvo -> Objects.equals(seatvo.isBePurchased(), true)).collect(Collectors.toList());
        if (lowSeatVO.size() == lowSeat.size()) {
            eventVO.setLowSellout(true);
        }
        //判断各种档次的票数与座位数是否相同，相同表示已经卖完了
        List<SeatVO> midSeatVO = seatPurchasedVOList.getMidPriceSeats().stream()
                //true表示已被购买，
                .filter(seatvo -> Objects.equals(seatvo.isBePurchased(), true)).collect(Collectors.toList());
        if (midSeatVO.size() == midSeat.size()) {
            eventVO.setLowSellout(true);
        }
        //判断各种档次的票数与座位数是否相同，相同表示已经卖完了
        List<SeatVO> highSeatVO = seatPurchasedVOList.getHighPriceSeats().stream()
                //true表示已被购买，
                .filter(seatvo -> Objects.equals(seatvo.isBePurchased(), true)).collect(Collectors.toList());
        if (highSeatVO.size() == highSeat.size()) {
            eventVO.setLowSellout(true);
        }
        return eventVO;
        //return event;
    }

    @Log
    @Override
    public Result deleteByIDs(List<Integer> eventIDs) throws Exception {
        // 支付宝支付
        String privateKey = FileUtil.readUtf8String(PathUtil.getResourcesPath() + "alipay_private_key.txt");
        String publicKey = FileUtil.readUtf8String(PathUtil.getResourcesPath() + "alipay_public_key.txt");
        AlipayClient alipayClient = new DefaultAlipayClient(aliPayConf.getServerUrl(), aliPayConf.getAppId(), privateKey, "json", "utf-8", publicKey, "RSA2");
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        for (Integer eventID : eventIDs) {

            List<Ticket> ticketList = ticketMapper.list(null, eventID, null);
            //key是订单号，一个订单号可能对应好几个座位
            Map<String, List<Ticket>> groupTickets = ticketList.stream().collect(Collectors.groupingBy(Ticket::getOrderNum));

            for (Map.Entry<String, List<Ticket>> entry : groupTickets.entrySet()) {
                List<Ticket> seatList = entry.getValue();
                Ticket ticket = seatList.get(0);
                Integer userID = ticket.getUserID();
                //获取用户手机号码
                String phoneNumber = userMapper.getByID(userID).getPhoneNumber();
                // 获取总价格
                final BigDecimal[] bigDecimal = {new BigDecimal(0)};
                seatList.forEach(ticket1 -> bigDecimal[0] = bigDecimal[0].add(ticket1.getTicketPrice()));
                BigDecimal totalPrice = bigDecimal[0].setScale(2, RoundingMode.DOWN);
                bizContent.put("trade_no", ticket.getTradeNo());
                bizContent.put("refund_amount", totalPrice);
                bizContent.put("out_request_no", "HZ01RF001");
                request.setBizContent(bizContent.toString());
                try {
                    AlipayTradeRefundResponse response = alipayClient.execute(request);
                    if (response.isSuccess()) {
                        if (StringUtils.equals(response.getCode(), "10000")) {
                            ticketMapper.updateStatus(ticket.getOrderNum(), ticket.getTradeNo(), "已退款");
                            // redis删除已售卖的座位号
                            redisService.setRemove(String.valueOf(ticket.getEventID()), seatList.stream().map(Ticket::getSeatID).toArray());
                        }
                    } else {
                        return Result.error("退款失败！");
                    }
                } catch (AlipayApiException e) {
                    log.error("支付退款请求发生异常！", e);
                    return Result.error("支付退款请求发生异常！");
                }
                aliSMS.cancelOrder(phoneNumber, ticket.getOrderNum());
            }
        }
        eventMapper.deleteByIDs(eventIDs);
        return Result.success("删除赛事并退款成功！");
    }

    @Log
    @Override
    public void save(Event event) {
        event.setUpdateTime(LocalDateTime.now());
        event.setCreateTime(LocalDateTime.now());
        eventMapper.save(event);
        // redis新增票务set集合，用于记录已卖出去的座位ID
        redisService.sSet(String.valueOf(event.getEventID()), -1);
    }

    @Log
    @Override
    public void update(Event event) {
        event.setUpdateTime(LocalDateTime.now());
        eventMapper.update(event);
    }

    @Override
    public PageBean page(Integer page, Integer pageSize, String eventName, Short place, Short onSale, Integer userID, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        int startIdx = (page-1)*pageSize;
        //2.执行查询
        List<Event> eventList = eventMapper.list(eventName, place, onSale, userID, begin, end, startIdx, pageSize);
        long count = eventMapper.listCount(eventName, place, onSale, userID, begin, end, startIdx, pageSize);
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(count, eventList);
        return pageBean;
    }

    @Override
    public void haltSale(Integer eventID) {
        //1-起售，2-停售
        eventMapper.changeSale(eventID, 2);
    }

    @Override
    public void onSale(Integer eventID) {
        //1-起售，2-停售
        eventMapper.changeSale(eventID, 1);
    }
}
